// Copyright 2013 Ronald Schlenker, www.technewlogic.de.
// 
// This file is part of Byond.
// 
// Byond is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
// 
// Byond is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with Byond.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using NLog;

namespace Byond.Logging
{
	public class UserLogger : IUserLogger, IDisposable
	{
		// Keine Container-field Injection hier
		public UserLogger(Logger logger)
		{
			_logger = logger;

			ThreadPool.QueueUserWorkItem(o =>
				{
					while (!_isDisposed)
					{
						_logCounterForThisSecond = 0;
						Thread.Sleep(TimeSpan.FromSeconds(1));
					}
				});

			_loggerThread = new Thread(LogThreadProc)
				{
					Name = "UserLogger",
					IsBackground = true
				};
			_loggerThread.Start();

			AttachDebugger();
		}

		private readonly Logger _logger;

		private readonly List<Tuple<string, bool>> _messageQueue = new List<Tuple<string, bool>>();
		private readonly AutoResetEvent _logEvent = new AutoResetEvent(false);

		private bool _isDisposed;
		private string _lastLogMessage = string.Empty;
		private int _logCounterForThisSecond;
		private readonly Thread _loggerThread;

		// IMP: Weak machen!
		public event Action<string> NewLogMessage;

		public void Log(string message, bool suppressEqualMessages = false)
		{
			lock (_messageQueue)
				_messageQueue.Add(new Tuple<string, bool>(message, suppressEqualMessages));

			_logEvent.Set();
		}

		private void LogThreadProc()
		{
			while (true)
			{
				_logEvent.WaitOne();

				List<Tuple<string, bool>> logMessages;
				lock (_messageQueue)
				{
					logMessages = _messageQueue.ToList();
					_messageQueue.Clear();
				}

				foreach (var logMessage in logMessages)
				{
					if ((logMessage.Item1 == _lastLogMessage || _logCounterForThisSecond >= 1000) && logMessage.Item2)
						continue;

					_lastLogMessage = logMessage.Item1;
					_logCounterForThisSecond++;

					_logger.Info(logMessage.Item1);
					if (NewLogMessage != null)
						NewLogMessage(logMessage.Item1);
				}
			}
		}

		public void Dispose()
		{
			_isDisposed = true;
			_loggerThread.Abort();
		}

		[Conditional("DEBUG")]
		private void AttachDebugger()
		{
			var debugListener = new DebugListener();
			debugListener.Writing += message => Log("DEBUG:  " + message);
		}
	}
}